﻿#include "ServiceParser.h"
#include "XyNetCompiler/CodeGenerator.h"
#include <boost/property_tree/info_parser.hpp>

namespace XyNet
{

	void ServiceParser::addCodeGenerator(shared_ptr<CodeGenerator> codeGenerator)
	{
		_codeGenerators.emplace_back(codeGenerator);
	}

	const filesystem::path& ServiceParser::getServiceFilePath() const
	{
		return _serviceFilePath;
	}

	const vector<string>* ServiceParser::getImports() const
	{
		return &_imports;
	}

	const string& ServiceParser::getPackage() const
	{
		return _package;
	}

	const vector<Service>* ServiceParser::getServices() const
	{
		return &_services;
	}

	const map<string, Error>* ServiceParser::getErrors() const
	{
		return &_errors;
	}

	const Error* ServiceParser::findError(const string& errorName)
	{
		auto iter = _errors.find(errorName);
		if (iter != _errors.end())
			return &iter->second;
		else
			return nullptr;
	}

	void ServiceParser::parse(const filesystem::path& serviceFilePath)
	{
		// 清除数据
		_serviceFilePath = serviceFilePath;
		_tree.clear();
		_imports.clear();
		_package.clear();
		_services.clear();
		_errors.clear();

		// 解析服务文件
		filesystem::ifstream fileStream(_serviceFilePath);
		boost::property_tree::read_info(fileStream, _tree);

		for (auto iter = _tree.begin(); iter != _tree.end(); ++iter)
		{
			if (!iter->second.data().empty())	// 没有子项目
			{
				if (iter->first == "Import")
					_imports.emplace_back(iter->second.data());
				else if (iter->first == "Package")
				{
					if (_package.empty())
						_package = iter->second.data();
					else
						throw std::runtime_error("只能有一个Package。");
				}
				else
					throw std::runtime_error("无效标志：" + iter->first);
			}
			else
			{
				if (iter->first == "Error")
				{
					if (_errors.empty())
						parseError(iter->second);	// 解析错误定义
					else
						throw std::runtime_error("只能有一个Error定义。");
				}
				else
				{
					// 解析服务
					_services.emplace_back(iter->first);
					parseService(&_services.back(), iter->second);
				}
			}
		}

		// 生成代码
		for (auto codeGenerator : _codeGenerators)
			codeGenerator->generator(this);
	}

	void ServiceParser::parseError(const boost::property_tree::ptree& errorTree)
	{
		for (auto iter = errorTree.begin(); iter != errorTree.end(); ++iter)
		{
			if (iter->second.data().empty())	// 有子项目
				throw std::runtime_error("错误不能有子项目。");
			else
			{
				auto result = _errors.insert(
					make_pair(iter->first, Error(iter->first, iter->second.data())));
				if (!result.second)
					throw std::runtime_error(("错误名称已经存在：" + iter->first).c_str());
			}
		}
	}

	void ServiceParser::parseService(Service* service, const boost::property_tree::ptree& serviceTree)
	{
		for (auto iter = serviceTree.begin(); iter != serviceTree.end(); ++iter)
		{
			if (!iter->second.data().empty())	// 没有子项目
				throw std::runtime_error("服务必须有子项目。");
			else
			{
				service->_methods.emplace_back(iter->first);
				parseMethod(&service->_methods.back(), iter->second);
			}
		}
	}

	void ServiceParser::parseMethod(Method* method, const boost::property_tree::ptree& methodTree)
	{
		for (auto iter = methodTree.begin(); iter != methodTree.end(); ++iter)
		{
			if (!iter->second.data().empty())	// 没有子项目
				throw std::runtime_error("方法必须有子项目。");
			else
			{
				if (iter->first == "Request")
					parseMethodRequestResponse(&method->_requestArguments, iter->second);
				else if (iter->first == "Response")
					parseMethodRequestResponse(&method->_responseArguments, iter->second);
				else if (iter->first == "Error")
					parseMethodError(&method->_errors, iter->second);
				else
					throw std::runtime_error(("未知标记：" + iter->first).c_str());
			}
		}
	}

	void ServiceParser::parseMethodRequestResponse(vector<pair<string, string>>* requestResponseArguments, const boost::property_tree::ptree& requestResponseTree)
	{
		for (auto iter = requestResponseTree.begin(); iter != requestResponseTree.end(); ++iter)
		{
			if (iter->second.data().empty())
				throw std::runtime_error("请求应答不能有子项目。");
			else
				requestResponseArguments->emplace_back(iter->first, iter->second.data());
		}
	}

	void ServiceParser::parseMethodError(
		vector<Error>* methodErrors, const boost::property_tree::ptree& methodErrorTree)
	{
		for (auto iter = methodErrorTree.begin(); iter != methodErrorTree.end(); ++iter)
		{
			auto errorName = iter->first;	// 方法错误忽略第二个参数
			// 查找错误是否有定义
			const Error* error = findError(errorName);
			if (!error)
				throw std::runtime_error(string("错误未定义：" + errorName).c_str());
			else
				methodErrors->emplace_back(*error);
		}
	}
}